home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 2 / BBS in a box - Trilogy II.iso / Files / Hyper / T / TIFFWindow1.1 / tiffgroup4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-04  |  8.6 KB  |  404 lines  |  [TEXT/KAHL]

  1. /*
  2.  * This software is copyright 1992 by Robert Morris.
  3.  * You may freely redistribute this software as shareware
  4.  * if you do so in the same form as you got it. If you find
  5.  * this software useful, please send $12 to:
  6.  *   Robert Morris
  7.  *   P.O. Box 1044
  8.  *   Harvard Square Station
  9.  *   Cambridge, MA 02238
  10.  *   ecognome@aol.com
  11.  * If you incorporate any of this software in any kind of
  12.  * commercial product, please send $2 per copy distributed
  13.  * to the above address.
  14.  */
  15.  
  16. /*
  17.  * Decode Group 4 TIFF compression. Based on CCITT Recommendation T.6,
  18.  * "Facsimile Coding Schemes and Coding Control Functions for Group 4
  19.  * Facsimile Apparatus," 1988, Fascicle VII.3.
  20.  */
  21.  
  22. #include "tiffinfo.h"
  23. #include "tifft4tables.h"
  24. #include "bits.h"
  25.  
  26. struct T6InfoRec{
  27.     TIFFPtr ti;
  28.     struct bits in;
  29.     struct bits out;
  30.     short *reference;    /* array of indices of changing elements */
  31.     short *nextref;    /* changing elements of this line */
  32. };
  33. typedef struct T6InfoRec *T6Info;
  34.  
  35. OSErr T6Line(T6Info);
  36. long T4Code(T6Info t6, long color);
  37. void T6References(T6Info t6, long *b1, long *b2);
  38. OSErr T6EmitSpan(T6Info t6, long length);
  39.  
  40. #define T6EOF(t6) TestBitsEOF(&(t6->in))
  41. #define T6Bit(t6) ReadBit(&(t6->in))
  42.  
  43. OSErr
  44. DecodeT6(TIFFPtr ti, char *in, long inlen, char *out, long outlen)
  45. {
  46.     long rowbytes;
  47.     OSErr err = 0;
  48.     T6Info t6 = 0;
  49.     long y, i;
  50.     
  51. #if 0
  52.     if(ti->t6Options != 0){
  53.         TIFFError(ti, -1, "\pUnrecognized T6 (Group 4) options.");
  54.         return(-1);
  55.     }
  56. #endif
  57.  
  58.     if(sizeof(t6->reference[0]) == 0 && ti->imageWidth > 31000){
  59.         TIFFError(ti, -1, "\pGroup 4 image is too wide.");
  60.         return(-1);
  61.     }
  62.     
  63.     if(InitT4Tables() != 0){
  64.         TIFFError(ti, -1, "\pOut of memory for T4 tables.");
  65.         return(-1);
  66.     }
  67.     
  68.     rowbytes = (ti->imageWidth + 7) / 8;
  69.     
  70.     t6 = (T6Info) NewPtr(sizeof(struct T6InfoRec));
  71.     if(t6 == 0){
  72.         TIFFError(ti, MemError(), "\pOut of memory.");
  73.         goto out;
  74.     }
  75.     t6->ti = ti;
  76.     if(NewBits(&(t6->in), (unsigned char *)in, inlen * 8, ti->fillOrder == 1, 0) < 0)
  77.         goto out;
  78.     if(NewBits(&(t6->out), (unsigned char *)out, outlen * 8, 1, 1) < 0)
  79.         goto out;
  80.     t6->reference = t6->nextref = 0;
  81.     t6->reference = (short *)NewPtr((ti->imageWidth+1) * sizeof(t6->reference[0]));
  82.     t6->nextref = (short *)NewPtr((ti->imageWidth+1) * sizeof(t6->reference[0]));
  83.     if(t6->reference == 0 || t6->nextref == 0){
  84.         TIFFError(ti, MemError(), "\pOut of memory.");
  85.         goto out;
  86.     }
  87.     t6->reference[0] = ti->imageWidth; /* first reference line is all white */
  88.     
  89.     for(y = 0; y < ti->imageLength; y++){
  90.         err = T6Line(t6);
  91.         if(err != 0)
  92.             goto out;
  93.     }
  94.  
  95. out:
  96.     FreeT4Tables();
  97.     if(t6->reference)
  98.         DisposPtr(t6->reference);
  99.     if(t6->nextref)
  100.         DisposPtr(t6->nextref);
  101.     if(t6)
  102.         DisposPtr(t6);
  103. #if 0
  104.     ti->err = 0;
  105.     return(0);
  106. #else
  107.     return((err != 0 || ti->err != 0) ? -1 : 0);
  108. #endif
  109. }
  110.  
  111.  
  112. /*
  113.  * Decode one scan line. Maintain reference bit-pointer to previous
  114.  * decoded scan line. Pad each output line to a byte boundary.
  115.  */
  116. OSErr
  117. T6Line(T6Info t6)
  118. {
  119.     long pos, savestart;
  120.     long bit, b4;
  121.     long b1, b2;
  122.     long run1, run2;
  123.     long nrp = 0, rp = 0;
  124.     short *nextref = t6->nextref;
  125.     short *reference = t6->reference;
  126.     long a0 = -1;
  127.     long a0color = 0; /* lines are assumed to start out white */
  128.     long width = t6->ti->imageWidth;
  129.     
  130.     savestart = TellBits(&(t6->out));
  131.     
  132.     while(a0 < width){
  133.         if(T6EOF(t6))
  134.             return(-1);
  135.             
  136.         while(rp > 0 && reference[rp] > a0)
  137.             rp -= 1;
  138.             
  139.         /* search forward for the first reference change after a0 */
  140.         while(reference[rp] <= a0)
  141.             rp += 1;
  142.         
  143.         /*
  144.          * Make sure b1 has an opposite color to a0.
  145.          * An odd reference index is a change to white.
  146.          * References[] does not have zero-length runs.
  147.          */
  148.         if(reference[rp] < width && (rp & 1) != a0color){
  149.             rp += 1;
  150.         }
  151.         b1 = reference[rp];
  152.     
  153.         if(reference[rp] < width)
  154.             b2 = reference[rp+1];
  155.         else
  156.             b2 = width;
  157.         
  158.         /*
  159.          * the first count of each line is from position 0, not a0, since
  160.          * a0 starts as -1.
  161.          */
  162.         if(a0 == -1){
  163.             b1 -= 1;
  164.             b2 -= 1;
  165.         }
  166.             
  167.         run1 = run2 = -1;
  168.         b4 = Peek4Bits(&(t6->in));
  169.         switch(b4){
  170.         case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15:
  171.             /* 1: V0 */
  172.             TossBits(&(t6->in), 1);
  173.             run1 = b1 - a0;
  174.             break;
  175.         case 6: case 14:
  176.             /* 011: VR1 */
  177.             TossBits(&(t6->in), 3);
  178.             run1 = b1 - a0 + 1;
  179.             break;
  180.         case 2: case 10:
  181.             /* 010: VL1 */
  182.             TossBits(&(t6->in), 3);
  183.             run1 = b1 - a0 - 1;
  184.             break;
  185.         case 4: case 12:
  186.             /* 001: horizontal mode */
  187.             TossBits(&(t6->in), 3);
  188.             run1 = T4Code(t6, a0color);
  189.             if(run1 < 0)
  190.                 return(-1);
  191.             run2 = T4Code(t6, !a0color);
  192.             if(run2 < 0)
  193.                 return(-1);
  194.             break;
  195.         case 8:
  196.             /* 0001: pass mode */
  197.             TossBits(&(t6->in), 4);
  198.             run1 = b2 - a0;
  199.             /* but switch back to original color */
  200.             run2 = 0;
  201.             break;
  202.         case 0:
  203.             TossBits(&(t6->in), 4);
  204.             Read2Bits(&(t6->in), bit);
  205.             switch(bit){
  206.             case 3:
  207.                 /* 000011: VR2 */
  208.                 run1 = b1 - a0 + 2;
  209.                 break;
  210.             case 1:
  211.                 /* 000010: VL2 */
  212.                 run1 = b1 - a0 - 2;
  213.                 break;
  214.             case 2:
  215.                 bit = T6Bit(t6);
  216.                 if(bit){
  217.                     /* 0000011: VR3 */
  218.                     run1 = b1 - a0 + 3;
  219.                 } else {
  220.                     /* 0000010: VL3 */
  221.                     run1 = b1 - a0 - 3;
  222.                 }
  223.                 break;
  224.             case 0:
  225.                 /* 000000: extension? */
  226.                 return(-1);
  227.             }
  228.             break;
  229.         }
  230.         
  231.         if(a0 == -1)
  232.             a0 += 1;
  233.             
  234.         WriteBitSpan(&(t6->out), a0color, run1);
  235.         a0 += run1;
  236.         if(nrp > 0 && run1 == 0)
  237.             nrp -= 1;
  238.         else
  239.             nextref[nrp++] = a0;
  240.         
  241.         if(run2 != -1){
  242.             WriteBitSpan(&(t6->out), !a0color, run2);
  243.             a0 += run2;
  244.             if(nrp > 0 && run2 == 0)
  245.                 nrp -= 1;
  246.             else
  247.                 nextref[nrp++] = a0;
  248.         } else {
  249.             a0color = !a0color;
  250.         }
  251.         
  252.         /*
  253.          * record the change for the next reference line.
  254.          * eliminate zero-width runs.
  255.          */
  256.     }
  257.             
  258.     if(a0 != width ||
  259.        TellBits(&(t6->out)) - savestart != width){
  260.         TIFFError(t6->ti, -1, "\pBad line length.");
  261.         return(-1);
  262.     }
  263.             
  264.     /* pad output line to a full byte */
  265.     pos = TellBits(&(t6->out));
  266.     while(pos & 7){
  267.         if(WriteBits(&(t6->out), 0, 1) < 0)
  268.             return(-1);
  269.         pos += 1;
  270.     }
  271.             
  272.     nextref[nrp++] = width;
  273.     t6->nextref = reference;
  274.     t6->reference = nextref;
  275.     
  276.     return(0);
  277. }
  278.  
  279. #if 0
  280. /*
  281.  * Emit a run of pixels all of the same color. Add the run length to a0.
  282.  * Invert the a0 color. The first run on each line is from position 0, not -1,
  283.  * even though a0 starts out as -1.
  284.  */
  285. OSErr
  286. T6EmitSpan(T6Info t6, long length)
  287. {
  288.     WriteBitSpan(&(t6->out), t6->a0color, length);
  289.         
  290.     if(t6->a0 == -1)
  291.         t6->a0 += 1;
  292.     t6->a0 += length;
  293.     t6->a0color = !t6->a0color;
  294.     
  295.     /*
  296.      * record the change for the next reference line.
  297.      * eliminate zero-width runs.
  298.      */
  299.     if(t6->nrp > 0 && length == 0)
  300.         t6->nrp -= 1;
  301.     else
  302.         t6->nextref[t6->nrp++] = t6->a0;
  303.     
  304. #if 0
  305.     if((t6->nrp & 1) != t6->a0color)
  306.         return(-1);
  307. #endif
  308.  
  309. #if 0
  310.     if((t6->a0 % t6->ti->imageWidth) != (TellBits(&(t6->out)) % t6->ti->imageWidth))
  311.         return(-1);
  312. #endif 
  313.  
  314.     return(0);
  315. }
  316.  
  317. /*
  318.  * Calculate b1 and b2. These are positions in the reference line, whereas
  319.  * a0 is a position in the current line. b1 is the first changing element
  320.  * to the right of a0, and of the opposite color to a0. b2 is the next changing
  321.  * element to the right of b1. b2 is used only in pass mode; maybe we shouldn't
  322.  * compute it always. This code calls the element above a0 on the reference line b0.
  323.  */
  324. void
  325. T6References(T6Info t6, long *b1, long *b2)
  326. {
  327.     short rp = t6->rp;
  328.     short *reference = t6->reference;
  329.     
  330.     while(rp > 0 && reference[rp] > t6->a0)
  331.         rp -= 1;
  332.         
  333.     /* search forward for the first reference change after a0 */
  334.     while(reference[rp] <= t6->a0)
  335.         rp += 1;
  336.     
  337.     /*
  338.      * Make sure b1 has an opposite color to a0.
  339.      * An odd reference index is a change to white.
  340.      * References[] does not have zero-length runs.
  341.      */
  342.     if(reference[rp] < t6->ti->imageWidth && (rp & 1) != t6->a0color){
  343.         rp += 1;
  344.     }
  345.     *b1 = reference[rp];
  346.  
  347.     if(reference[rp] < t6->ti->imageWidth)
  348.         *b2 = reference[rp+1];
  349.     else
  350.         *b2 = t6->ti->imageWidth;
  351.     
  352.     t6->rp = rp;
  353.     
  354.     /*
  355.      * the first count of each line is from position 0, not a0, since
  356.      * a0 starts as -1.
  357.      */
  358.     if(t6->a0 == -1){
  359.         *b1 -= 1;
  360.         *b2 -= 1;
  361.     }
  362. }
  363. #endif
  364.  
  365. /*
  366.  * Read (and consume) one T4 modified Huffman code. Return the length.
  367.  * T6 uses the T4 length codes when all else fails. If there is a makeup
  368.  * code, read it as well as the terminal code.
  369.  */
  370. long
  371. T4Code(T6Info t6, long color)
  372. {
  373.     long bit, state;
  374.     struct t4table *table;
  375.     long len; /* accumulate makeup lengths */
  376.     
  377.     table = &(t4table[color][0]);
  378.     state = 0;
  379.     len = 0;
  380.     while(table[state].terminating == 0){
  381.         if(table[state].makeup){
  382.             /* multiple makeup codes do occur */
  383. #if 0
  384.             if(len != 0){
  385.                 /* multiple makeup codes: are they allowed? */
  386.                 return(-1);
  387.             }
  388. #endif
  389.             len += table[state].on0;
  390.             state = 0;
  391.         }
  392.         if(T6EOF(t6))
  393.             return(-1);
  394.         bit = T6Bit(t6);
  395.         if(bit)
  396.             state = table[state].on1;
  397.         else
  398.             state = table[state].on0;
  399.         if(state == 0 || state >= t4tablelen[color])
  400.             return(-1);
  401.     }
  402.     return(len + table[state].on0);
  403. }
  404.